class Tools {
    $ = id => document.getElementById(id)
    _c = id => document.createElement(id)



}
//按钮事件 类
class mouseEvent extends Tools {
    constructor(snakContext, f) {
        super()
        this.begin = this.$('begin')//开始游戏
        this.stop = this.$('stop')//暂停游戏
        this.anew = this.$('anew')//重新开始
        this.map = this.$('map')
        this.f = f
        //把Sank 的实例当作参数传进来然后再这个类里面 用这个参数
        //就可以调用Sank类里面的方法
        //参数引进之前先用instanceof进行判断他是不是 我们想要的实例

        if (snakContext instanceof Snak) {
            this.s = snakContext
            this.btnEvent()
        } else {
            alert('请传入有效实例')
        }

    }
    //把三个按钮封装到一个函数里面 这样 利于上面队参数的判断
    btnEvent = () => {
        this.begin.onclick = this.beginGame
        this.stop.onclick = this.stopGame
        this.anew.onclick = this.anewGame
    }
    //开始按钮
    beginGame = () => {
        /*  this.begin.disabled = true; */
        if (this.timer) {
            clearInterval(this.timer)
        }//防抖
        this.timer = setInterval(() => {
            this.s.run()
        }, 100)

        this.f.food()

    }
    //暂停按钮
    stopGame = () => {
        clearInterval(this.timer)
    }
    //重新开始按钮
    anewGame = () => {
        this.disabled = true;
        // 利用map 方法给数组中的每一个对象中的x y重新赋值

        /* let count = 3
        let newBody = this.s.body.map(item => {
            count--//因为他会给数组中的每一个对象去赋值 所以就会循环 每次渐渐
            return {
                x: count,
                y: 0,
                oldNode: item.oldNode
            }
        }) */
        //因为老有多的部分在外面重新开始的时候 最初数据给蛇蛇
        // 先清空 页面 
        this.f.remove()
        s.span.innerHTML = 0
        s.count = 0;
        this.map.innerHTML = ""
        this.s.body = [
            {
                x: 2,
                y: 0
            },
            {
                x: 1,
                y: 0
            },
            {
                x: 0,
                y: 0
            }

        ];

        this.s.display()


        this.s.diretion = 'right'
        clearInterval(this.timer)
    }

}
//蛇蛇 类
class Snak extends Tools {
    constructor(f) {
        super()
        //蛇蛇的身体
        this.body = [
            { x: 2, y: 0 },//头部
            { x: 1, y: 0 },
            { x: 0, y: 0 }];//尾部
        this.width = 15;
        this.height = 15;
        this.map = this.$('map');
        this.btns = document.querySelectorAll('button')

        this.diretion = 'right'//让蛇蛇默认向右游动
        this.f = f;
        this.count = 0;
        this.span = this.$('span')


        // 头部距离左边 上边的距离

        this.keyboardEvent();
    }





    //画蛇蛇；
    display = () => {

        this.body.forEach(item => {
            if (item.oldNode) {
                this.map.removeChild(item.oldNode)
            }
            //先生成一个小的div元素 
            let div = this._c('div');
            div.className = 'div'
            div.style.width = this.width + 'px';//这里一定要写style
            div.style.height = this.height + 'px';
            div.style.backgroundColor = 'pink';
            div.style.border = '#000 solid 1px';
            //让蛇蛇在一排显示
            div.style.position = 'absolute';
            div.style.left = item.x * this.width + 'px';
            div.style.top = item.y * this.height + 'px';
            //生成以后要上传

            item.oldNode = div;//把这个元素暂时存到对象里
            this.map.appendChild(div)


        });
        this.divs = document.querySelectorAll(".div")
        this.ssL = this.divs[0].offsetLeft
        this.ssT = this.divs[0].offsetTop
        this.divs[0].className = 'ss'

    }




    //让蛇蛇跑；
    run = () => {
        //控制body里面的xy让蛇蛇移动
        //首先 删除尾巴 斌且用let拿到他的返回值；
        let final = this.body.pop()
        let first = { ...this.body[0] }//通过展开拿到头部
        let { x } = first;
        let { y } = first;
        switch (this.diretion) {
            case 'left':
                x -= 1
                break;
            case 'up':
                y -= 1
                break;
            case 'right':
                x += 1
                break;
            case 'down':
                y += 1
                break;
        }
        //这时小蛇的方向 可以通过 改变 xy 的值去控制它
        //把x 和y 的值 赋给 删除的尾部 
        final.x = x;
        final.y = y;
        //吃到食物变长了
        if (this.ssL === this.f.ranL && this.ssT === this.f.ranT) {
            this.count++
            this.span.innerHTML = this.count
            this.body.push({ x, y })
            this.f.remove()
            this.f.food()
        }

        this.body.unshift(final)//重新上传到数组中
        this.display()//重新渲染页面
        //边界判定暂听了
        if (this.ssL < 0 || this.ssL > this.map.offsetWidth - this.width || this.ssT < 0 || this.ssT > this.map.offsetHeight - this.height || (this.ssT < 0 && this.diretion == "up")) {
            alert('你的得分是' + this.count)
            b.stopGame()
        }
        //咬到自己尾巴
        /* for (let i = 1; i < this.divs.length; i++) {
            if (this.divs[0].offsetLeft === this.divs[i].offsetLeft && this.divs[0].offsetLeft === this.divs[i].offsetTop) {
                console.log(11);
            }
        }
 */
    }
    //控制蛇蛇的方向
    keyboardEvent() {
        //首先把事件绑定到全局上面拿到键盘的keyCODE的值
        document.onkeydown = e => {
            switch (e.keyCode) {
                case 37:
                    if (this.diretion != 'right') {
                        this.diretion = 'left'
                    }

                    break;


                case 38:
                    if (this.diretion != 'down') {
                        this.diretion = 'up'
                    }

                    break;
                case 39:
                    if (this.diretion != 'left') {
                        this.diretion = 'right'
                    }
                    break;
                case 40:
                    if (this.diretion != 'up') {
                        this.diretion = 'down'
                    }
                    break;


            }
        }

    }



}
//食物
class Food extends Tools {
    constructor() {
        super()
        this.map = this.$('map')
        this.mapW = this.map.offsetWidth;
        this.mapH = this.map.offsetHeight;
        this.width = 15;
        this.height = 15;





    }
    randomNum() {
        let ranL = Math.ceil(Math.random() * (this.mapW - this.width));
        let ranT = Math.ceil(Math.random() * (this.mapH - this.height));
        if (ranL % 15 === 0 && ranT % 15 === 0) {
            this.ranL = ranL
            this.ranT = ranT

        } else {
            this.randomNum()
        }

    }
    //生成食物
    food = () => {
        if (this.div) {
            return
        }
        let div = this._c('div')
        div.style.width = this.width + 'px'
        div.style.height = this.height + 'px'
        div.className = 'food'

        this.randomNum()
        div.style.left = this.ranL + 'px';
        div.style.top = this.ranT + 'px';
        this.div = div;
        this.map.appendChild(div)
    }
    //清除食物

    remove = () => {
        this.map.removeChild(this.div)
        this.div = null
    }

}

//调用
let f = new Food()
let s = new Snak(f)
s.display()
let b = new mouseEvent(s, f)




























